/*
 * data2source.cpp
 *
 *  Created on: 2016年6月15日
 *      Author: guyadong
 */
#include <string>
#include <cstdio>
#include <iostream>
#include <sstream>
#include <algorithm>

#include "file_utilits.h"
#include "assert_macros.h"
#include "zlib_wrapper.h"
#include "data2source.h"
namespace gdface{
#define _CONTENT_  ${content}
#define _VAR_NAME_ ${var_name}
#define _BIN_ARRAY_TEMPLATE(v,c) "\nconst char "#v"[]={"#c"\n};\n"
#define BIN_ARRAY_TEMPLATE(v,c) _BIN_ARRAY_TEMPLATE(v,c)
#define _STRING_ARRAY_TEMPLATE(v,c) "\nconst char* "#v"[]={"#c"\n};\n"
#define STRING_ARRAY_TEMPLATE(v,c) _STRING_ARRAY_TEMPLATE(v,c)
#define _SIZE_VAR_TEMPLATE(v,s) "\nconst size_t "#v"="#s";\n"
#define SIZE_VAR_TEMPLATE(v,s) _SIZE_VAR_TEMPLATE(v,s)
#define _DATA_INFO_MAP_VAR_TEMPLATE(v,c) "\nconst code_data_info_map_type "#v"={"#c"\n};\n"
#define DATA_INFO_MAP_VAR_TEMPLATE(v,c) _DATA_INFO_MAP_VAR_TEMPLATE(v,c)
#define _ORIGINAL_SUFFIX_ _original_size
static const std::string CONTENT=DEF_TO_STRING(_CONTENT_);
static const std::string VAR_NAME=DEF_TO_STRING(_VAR_NAME_);
static const std::string ORIGINAL_SUFFIX=DEF_TO_STRING(_ORIGINAL_SUFFIX_);
static const std::string ARRAY_VAR = BIN_ARRAY_TEMPLATE(_VAR_NAME_, _CONTENT_);
static const std::string STRING_ARRAY_VAR = STRING_ARRAY_TEMPLATE(_VAR_NAME_, _CONTENT_);
static const std::string SIZE_VAR = SIZE_VAR_TEMPLATE(_VAR_NAME_, _CONTENT_);
static const std::string DATA_INFO_MAP_VAR = DATA_INFO_MAP_VAR_TEMPLATE(_VAR_NAME_, _CONTENT_);
static const std::string  FILE_HEAD= R"(#include <unordered_map>
#include <string>
typedef struct _program_file_info{
	const char* ptr;
	size_t size;
	size_t original_size;
}code_data_info;
using code_data_info_map_type=std::unordered_map<std::string,code_data_info>;
)";

/*
 * 用value替换source_template中的name
 * */
std::string render_template(const std::string &source_template,const std::string &name,const std::string &value){
	auto pos=source_template.find(name);
	throw_if_msg(pos==std::string::npos,std::string("invalid source_template,not  include flag:").append(name))
	auto temp=source_template;
	temp.replace(pos,name.size(),value);
	return temp;
}
/*
 * 将流中的数据根据source_template转为二进制数组的代码片段
 * 返回代码片段字符串
 * */
std::string to_source_str(const std::string &source_template, std::istream &is){
	std::basic_ostringstream<char> stream;
	stream.flags(std::ios::right | std::ios::hex | std::ios::showbase);
	char c;
	for(int i=0; is.get(c);++i){
		if(i)stream	<<",";
		// 满8个字符自动换行
		if (0 == (i & 7))stream << std::endl;		
		stream << "char(";
		stream.width(4);
		stream.fill(' ');
		stream << int(uint8_t(c));
		stream<< ")";
	}
	return render_template(source_template,CONTENT,stream.str());
}
std::string to_source_str(const std::string &source_template, const char *src_ptr,size_t size){
	throw_if(nullptr==src_ptr)
	std::basic_istringstream<char> istream;
	istream.str(std::string(src_ptr, size));
	return to_source_str(source_template,istream);
}
std::string to_source_str(const std::string &source_template, const std::string &bin_src){
	return to_source_str(source_template,bin_src.data(),bin_src.size());
}
std::string to_source_str(const std::string &source_template, const std::vector<uint8_t> &bin_src){
	return to_source_str(source_template,(const char *)bin_src.data(),bin_src.size());
}
/*
 * 将src_ptr指向的数据转为名为name的数组定义代码片段
 * */
std::string make_var_array(const std::string &name, const char *src_ptr,size_t size){
	throw_if(name.empty()||nullptr==src_ptr)
	return to_source_str(render_template(ARRAY_VAR,VAR_NAME,name),src_ptr,size);
}
std::string make_size_var(const std::string &name,size_t size){
	std::basic_ostringstream<char> ostream;
	ostream<<size;
	auto out=render_template(SIZE_VAR,VAR_NAME,name);
	return render_template(out,CONTENT,ostream.str());
}
/*
 * 将file文件内容转为名为name的数组定义代码片段
 * */
std::string make_var_array(const std::string &name, std::string file){
	throw_if(name.empty()||file.empty())
	auto bin=load_binary_file(file.data());
	auto out=make_size_var(name+ORIGINAL_SUFFIX,bin.size());
	out.append(to_source_str(render_template(ARRAY_VAR,VAR_NAME,name),zlib::mem_compress(bin)));
	return out;
}
/*
 * 将字符串转为名为name字符串数组变量的代码片段
 * */
template<typename _InputIterator>
typename std::enable_if<std::is_base_of<std::input_iterator_tag, typename _InputIterator::iterator_category>::value
					  &&std::is_base_of<std::string, typename _InputIterator::value_type>::value, std::string>::type
make_string_array_var(_InputIterator first, _InputIterator last,const std::string &name){
	auto source_template=render_template(STRING_ARRAY_VAR,VAR_NAME,name);
	std::basic_ostringstream<char> stream;
	for (int count=0; first != last; ++first,++count){
		if(count)stream<<",";
		stream << std::endl<<"\t\""<<*first<<"\"";
	}
	return render_template(source_template,CONTENT,stream.str());
}
#define _TMP_BUFFER_SIZE 256
/*
 * 将文件名字符串转为名为name字符串map变量的代码片段
 *  */
template<typename _InputIterator>
typename std::enable_if<std::is_base_of<std::input_iterator_tag, typename _InputIterator::iterator_category>::value
					  &&std::is_base_of<std::string, typename _InputIterator::value_type>::value, std::string>::type
make_data_info_map_var(_InputIterator first, _InputIterator last,const std::string &name){
	auto source_template=render_template(DATA_INFO_MAP_VAR,VAR_NAME,name);
	std::basic_ostringstream<char> stream;
	char buffer[_TMP_BUFFER_SIZE];
	for (int count=0; first != last; ++first,++count){
		if(count)stream<<",";
		auto filename=*first;
		auto ptr_var=replase_dot(filename);
		auto original_size_var=ptr_var+ORIGINAL_SUFFIX;
		std::snprintf(buffer,_TMP_BUFFER_SIZE,"\n\t{\"%s\",code_data_info{%s,sizeof(%s),%s}}",filename.data(),ptr_var.data(),ptr_var.data(),original_size_var.data());
		stream<<buffer;
	}
	return render_template(source_template,CONTENT,stream.str());
}
/*
 * 将content中的所有字符串转为名为name字符串数组变量的代码片段
 * */
std::string make_string_array_var(const std::string &name,const std::vector<std::string>&content) {
	return make_string_array_var(content.begin(), content.end(), name);
}
/*
 * 将content中的所有字符串转为名为name字符串数组变量的代码片段
 * */
std::string make_data_info_map_var(const std::string &name,const std::unordered_set<std::string>&content) {
	return make_data_info_map_var(content.begin(), content.end(), name);
}

std::string make_head(){
	return FILE_HEAD;
}
std::string replase_dot(const std::string &src) {
	auto dst = src;
	std::replace(dst.begin(), dst.end(),'.', '_');
	return dst;
}
}/*namespace gdface*/


